home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / ircle 1.5.1 / source / TCP Libraries / TCPConnections.unit next >
Encoding:
Text File  |  1993-03-15  |  17.6 KB  |  655 lines  |  [TEXT/PJMM]

  1. unit TCPConnections;
  2.  
  3. { From Peter's PNL Libraries }
  4. { Copyright 1992 Peter N Lewis }
  5. { This source may be used for any non-commercial purposes as long as I get a mention }
  6. { in the About box and Docs of any derivative program.  It may not be used in any commercial }
  7. { application without my permission }
  8.  
  9. interface
  10.  
  11. uses
  12.     TCPTypes, TCPStuff;
  13.  
  14. const  { Tuning parameters }
  15.     max_connections = 20;
  16.     tooManyConnections = -23099;
  17.     TO_FindAddress = 40 * 60;
  18.     TO_FindName = 40 * 60;
  19.     TO_ActiveOpen = 20 * 60;
  20.     TO_Closing = 20 * 60;
  21.     TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  22.  
  23. const
  24.     any_connection = 0;    { Pass to GetConnectionEvent }
  25.     no_connection = -1;    { Guaranteed invalid connection }
  26.  
  27. type
  28.     connectionIndex = longInt;
  29.     connectionEvent = (C_NoEvent, C_Found, C_SearchFailed, C_NameFound, C_NameSearchFailed,{}
  30.         C_Established, C_FailedToOpen, C_Closing, C_Closed, C_CharsAvailable, C_HeartBeat);
  31.     connectionEventRecord = record
  32.             event: connectionEvent;
  33.             connection: connectionIndex;
  34.             tcpc: TCPConnectionPtr;
  35.             dataptr: ptr;
  36.             value: longInt;
  37.             timedout: boolean;
  38.         end;
  39.  
  40. function InitConnections: OSErr;
  41. procedure CloseConnections;
  42. procedure TerminateConnections;
  43. function CanQuit: boolean;
  44. { After Terminate, keep calling GetConnectionEvent(any_connection,cer) until CanQuit is true, then Finish }
  45. procedure FinishConnections;
  46. procedure FinishEverything;  { Or just call FinishEverything }
  47. function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  48. function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  49. procedure FindString (hostIP: longInt; var s: str255);
  50. function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  51. function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  52. procedure CloseConnection (cp: connectionIndex);
  53. procedure AbortConnection (cp: connectionIndex); { Violently close connection }
  54. function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  55. { Pass any_connection for any event, otherwise cp specifies the event }
  56. procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  57. procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  58. procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  59. procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  60. procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  61. procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks, 0 disables heartbeat }
  62.  
  63. implementation
  64.  
  65. const
  66.     TCPCMagic = 'TCPC';
  67.     TCPCBadMagic = 'badc';
  68.  
  69. type
  70.     myHostInfo = record
  71.             hi: hostInfo;
  72.             done: signedByte;
  73.         end;
  74.     myHostInfoPtr = ^myHostInfo;
  75.     statusType = (CS_None, CS_Searching, CS_NameSearching, CS_Opening, CS_Established, CS_Closing);
  76.     connectionRecord = record
  77.             magic: OSType;
  78.             conmagic: longInt;
  79.             tcpc: TCPConnectionPtr;
  80.             laststate: TCPStateType; { DEBUG }
  81.             status: statusType;
  82.             cacheFaultReturnP: myHostInfoPtr;
  83.             closedone: boolean;
  84.             timeout: longInt;
  85.             dataptr: ptr;
  86.             heartbeat: longInt; { Time for next heartbeat }
  87.             period: longInt; { Ticks per heartbeat }
  88.             tcpstates: packed array[TCPStateType] of boolean; { DEBUG }
  89.             constates: packed array[connectionEvent] of boolean; { DEBUG }
  90.         end;
  91.  
  92. var
  93.     connections: array[1..max_connections] of connectionRecord;
  94.     connectionItem: connectionIndex;
  95.     dnrptr: ptr;
  96.     connectionmagic: longInt;
  97.  
  98. function ValidConnectionSafe (var cp: connectionIndex): boolean;
  99.     var
  100.         ocp: longInt;
  101.         vc: boolean;
  102.     begin
  103.         vc := false;
  104.         ocp := cp;
  105.         cp := cp mod (max_connections + 1);
  106.         if cp > 0 then
  107.             if connections[cp].magic = TCPCMagic then
  108.                 if connections[cp].conmagic = ocp then
  109.                     vc := true;
  110.         ValidConnectionSafe := vc;
  111.     end;
  112.  
  113. function ValidConnection (var cp: connectionIndex): boolean;
  114.     var
  115.         vc: boolean;
  116.     begin
  117.         vc := ValidConnectionSafe(cp);
  118.         if not vc then
  119.             DebugStr('Invalid Connection');
  120.         ValidConnection := vc;
  121.     end;
  122.  
  123. procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  124.     begin
  125.         if ValidConnection(cp) then
  126.             connections[cp].dataptr := dataptr;
  127.     end;
  128.  
  129. procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  130.     begin
  131.         if ValidConnectionSafe(cp) then
  132.             dataptr := connections[cp].dataptr
  133.         else
  134.             dataptr := nil;
  135.     end;
  136.  
  137. procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  138.     begin
  139.         if ValidConnection(cp) then
  140.             connections[cp].timeout := timeout;
  141.     end;
  142.  
  143. procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  144.     begin
  145.         if ValidConnection(cp) then
  146.             timeout := connections[cp].timeout
  147.         else
  148.             timeout := -1;
  149.     end;
  150.  
  151. procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks }
  152.     begin
  153.         if ValidConnection(cp) then begin
  154.             if (n < 1) or (n = maxLongInt) then begin
  155.                 connections[cp].period := maxLongInt;
  156.                 connections[cp].heartbeat := maxLongInt;
  157.             end
  158.             else begin
  159.                 connections[cp].period := n;
  160.                 connections[cp].heartbeat := TickCount + n;
  161.             end;
  162.         end;
  163.     end;
  164.  
  165. procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  166.     begin
  167.         if ValidConnectionSafe(cp) then
  168.             tcpc := connections[cp].tcpc
  169.         else
  170.             tcpc := nil;
  171.     end;
  172.  
  173. function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  174.     begin
  175.         if con = nil then
  176.             MyTCPState := T_Closed
  177.         else
  178.             MyTCPState := TCPState(con);
  179.     end;
  180.  
  181. {$S Init}
  182. function InitConnections: OSErr;
  183.     var
  184.         oe, ooe: OSErr;
  185.         i: connectionIndex;
  186.     begin
  187.         for i := 1 to max_connections do
  188.             connections[i].magic := TCPCBadMagic;
  189.         connectionmagic := 0;
  190.         connectionItem := 1;
  191.         oe := TCPInit;
  192.         if oe = noErr then begin
  193.             oe := TCPOpenResolver(dnrptr);
  194.             if oe <> noErr then
  195.                 TCPFinish;
  196.         end;
  197.         InitConnections := oe;
  198.     end;
  199.  
  200. {$S Term}
  201. procedure TerminateConnections;
  202.     var
  203.         i: connectionIndex;
  204.         oe: OSErr;
  205.     begin
  206.         for i := 1 to max_connections do
  207.             with connections[i] do
  208.                 if magic = TCPCMagic then
  209.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  210.                         if TCPState(tcpc) <> T_Closed then
  211.                             oe := TCPAbort(tcpc);
  212.     end;
  213.  
  214. {$S Term}
  215. procedure CloseConnections;
  216.     var
  217.         i: connectionIndex;
  218.         oe: OSErr;
  219.     begin
  220.         for i := 1 to max_connections do
  221.             with connections[i] do
  222.                 if magic = TCPCMagic then
  223.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  224.                         if TCPState(tcpc) <> T_Closed then
  225.                             oe := TCPClose(tcpc, nil);
  226.     end;
  227.  
  228. {$S Term}
  229. function CanQuit: boolean;
  230.     var
  231.         i: connectionIndex;
  232.     begin
  233.         CanQuit := true;
  234.         for i := 1 to max_connections do
  235.             if connections[i].magic = TCPCMagic then
  236.                 CanQuit := false;
  237.     end;
  238.  
  239. {$S Term}
  240. procedure FinishConnections;
  241.     begin
  242.         TCPCloseResolver(dnrptr);
  243.         TCPFinish;
  244.     end;
  245.  
  246. {$S Term}
  247. procedure FinishEverything;
  248.     var
  249.         cer: connectionEventRecord;
  250.         dummy: boolean;
  251.         er: eventrecord;
  252.         oe: OSErr;
  253.     begin
  254.         TerminateConnections;
  255.         while not CanQuit do begin
  256.             if GetConnectionEvent(any_connection, cer) then begin
  257.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  258.             end
  259.             else
  260.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  261.         end;
  262.         FinishConnections;
  263.     end;
  264.  
  265. {$S}
  266. function CreateConnection (var cp: connectionIndex; dp: ptr): OSErr;
  267.     var
  268.         ts: TCPStateType;
  269.         ce: connectionEvent;
  270.     begin
  271.         connectionmagic := connectionmagic + max_connections + 1;
  272.         cp := 1;
  273.         while (connections[cp].magic = TCPCMagic) and (cp < max_connections) do
  274.             cp := cp + 1;
  275.         with connections[cp] do begin
  276.             if magic = TCPCMagic then
  277.                 CreateConnection := tooManyConnections
  278.             else begin
  279.                 magic := TCPCMagic;
  280.                 conmagic := cp + connectionmagic;
  281.                 closedone := false;
  282.                 tcpc := nil;
  283.                 status := CS_None;
  284.                 cacheFaultReturnP := nil;
  285.                 timeout := maxlongInt;
  286.                 dataptr := dp;
  287.                 period := maxLongInt;
  288.                 heartbeat := maxLongInt;
  289.                 CreateConnection := noErr;
  290.                 cp := cp + connectionmagic;
  291.  
  292.                 for ce := C_NoEvent to C_HeartBeat do
  293.                     constates[ce] := false;
  294.                 for ts := T_WaitingForOpen to T_Unknown do
  295.                     tcpstates[ts] := false;
  296.             end;
  297.         end;
  298.     end;
  299.  
  300. procedure DestroyConnection (var cp: connectionIndex);
  301.     begin
  302.         if ValidConnection(cp) then
  303.             connections[cp].magic := TCPCBadMagic;
  304.         cp := -1;
  305.     end;
  306.  
  307. function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  308.     var
  309.         oe: OSErr;
  310.         cpi: connectionIndex;
  311.     begin
  312.         oe := CreateConnection(cp, dataptr);
  313.         if oe = noErr then begin
  314.             cpi := cp;
  315.             if ValidConnection(cpi) then begin
  316.                 with connections[cpi] do begin
  317.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  318.                     if cacheFaultReturnP = nil then
  319.                         oe := memFullErr
  320.                     else begin
  321.                         cacheFaultReturnP^.done := 0;
  322.                         oe := TCPStrToAddr(dnrptr, hostName, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  323.                         if oe = cacheFault then begin
  324.                             timeout := TickCount + TO_FindAddress;
  325.                             oe := noErr;
  326.                         end
  327.                         else begin
  328.                             cacheFaultReturnP^.done := -1;
  329.                             cacheFaultReturnP^.hi.rtnCode := oe;
  330.                         end;
  331.                         status := CS_Searching;
  332.                     end;
  333.                     if oe <> noErr then begin
  334.                         if cacheFaultReturnP <> nil then
  335.                             DisposPtr(ptr(cacheFaultReturnP));
  336.                         DestroyConnection(cp);
  337.                     end;
  338.                 end;
  339.             end;
  340.         end;
  341.         FindAddress := oe;
  342.     end;
  343.  
  344. procedure FindString (hostIP: longInt; var s: str255);
  345.     begin
  346.         TCPAddrToStr(dnrptr, hostIP, s);
  347.     end;
  348.  
  349. function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  350.     var
  351.         oe: OSErr;
  352.         cpi: connectionIndex;
  353.     begin
  354.         oe := CreateConnection(cp, dataptr);
  355.         if oe = noErr then begin
  356.             cpi := cp;
  357.             if ValidConnection(cpi) then begin
  358.                 with connections[cpi] do begin
  359.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  360.                     if cacheFaultReturnP = nil then
  361.                         oe := memFullErr
  362.                     else begin
  363.                         cacheFaultReturnP^.done := 0;
  364.                         oe := TCPAddrToName(dnrptr, hostIP, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  365.                         if oe = cacheFault then begin
  366.                             timeout := TickCount + TO_FindName;
  367.                             oe := noErr;
  368.                         end
  369.                         else begin
  370.                             cacheFaultReturnP^.done := -1;
  371.                             cacheFaultReturnP^.hi.rtnCode := oe;
  372.                         end;
  373.                         status := CS_NameSearching;
  374.                     end;
  375.                     if oe <> noErr then begin
  376.                         if cacheFaultReturnP <> nil then
  377.                             DisposPtr(ptr(cacheFaultReturnP));
  378.                         DestroyConnection(cp);
  379.                     end;
  380.                 end;
  381.             end;
  382.         end;
  383.         FindName := oe;
  384.     end;
  385.  
  386. function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  387.     var
  388.         oe: OSErr;
  389.         cpi: connectionIndex;
  390.     begin
  391.         oe := CreateConnection(cp, dataptr);
  392.         if oe = noErr then begin
  393.             cpi := cp;
  394.             if ValidConnection(cpi) then
  395.                 with connections[cpi] do begin
  396.                     oe := TCPPassiveOpen(tcpc, buffersize, localPort, remotehost, remoteport, nil);
  397.                     timeout := TickCount + TO_PassiveOpen;
  398.                     status := CS_Opening;
  399.                     if oe <> noErr then
  400.                         DestroyConnection(cp);
  401.                 end;
  402.         end;
  403.         NewPassiveConnection := oe;
  404.     end;
  405.  
  406. function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  407.     var
  408.         oe: OSErr;
  409.         cpi: connectionIndex;
  410.     begin
  411.         oe := CreateConnection(cp, dataptr);
  412.         if oe = noErr then begin
  413.             cpi := cp;
  414.             if ValidConnection(cpi) then
  415.                 with connections[cpi] do begin
  416.                     oe := TCPActiveOpen(tcpc, buffersize, 0, remotehost, remoteport, nil);
  417.                     timeout := TickCount + TO_ActiveOpen;
  418.                     status := CS_Opening;
  419.                     if oe <> noErr then
  420.                         DestroyConnection(cp);
  421.                 end;
  422.         end;
  423.         NewActiveConnection := oe;
  424.     end;
  425.  
  426. procedure CloseConnection (cp: connectionIndex);
  427.     var
  428.         oe: OSErr;
  429.     begin
  430.         if ValidConnection(cp) then
  431.             with connections[cp] do begin
  432.                 if not closedone then begin
  433.                     if MyTCPState(tcpc) <> T_Closed then begin
  434.                         oe := TCPClose(tcpc, nil);
  435.                     end;
  436.                     closedone := true;
  437.                 end;
  438.                 status := CS_Closing;
  439.                 timeout := TickCount + TO_Closing;
  440.             end;
  441.     end;
  442.  
  443. procedure AbortConnection (cp: connectionIndex);
  444.     var
  445.         oe: OSErr;
  446.     begin
  447.         if ValidConnection(cp) then
  448.             with connections[cp] do begin
  449.                 if MyTCPState(tcpc) <> T_Closed then
  450.                     oe := TCPAbort(tcpc);
  451.                 status := CS_Closing;
  452.                 timeout := TickCount + TO_Closing;
  453.             end;
  454.     end;
  455.  
  456. function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  457.     procedure HandleConnection (cp: connectionIndex);
  458.         var
  459.             oe: OSErr;
  460.             dummysp: stringPtr;
  461.             l: integer;
  462.             rcp: connectionIndex;
  463.         begin
  464.             with connections[cp] do begin
  465.                 rcp := conmagic;
  466.                 cer.connection := rcp;
  467.                 cer.tcpc := tcpc;
  468.                 cer.dataptr := dataptr;
  469.                 cer.timedout := false;
  470.                 case status of
  471.                     CS_NameSearching: 
  472.                         with cacheFaultReturnP^, hi do begin
  473.                             if done <> 0 then begin
  474.                                 if rtnCode = noErr then begin
  475.                                     cer.event := C_NameFound;
  476.                                     SanitizeHostName(rtnHostName);
  477.                                     stringHandle(cer.value) := NewString(rtnHostName);
  478.                                 end
  479.                                 else begin
  480.                                     cer.event := C_NameSearchFailed;
  481.                                     cer.value := rtnCode;
  482.                                 end
  483.                             end
  484.                             else if TickCount > timeout then begin
  485.                                 cer.event := C_NameSearchFailed;
  486.                                 cer.value := 1;
  487.                                 cer.timedout := true;
  488.                             end;
  489.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  490.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  491.                                     DisposPtr(ptr(cacheFaultReturnP));
  492.                                 cacheFaultReturnP := nil;
  493.                                 DestroyConnection(rcp);
  494.                             end; {if}
  495.                         end; {with}
  496.                     CS_Searching: 
  497.                         with cacheFaultReturnP^, hi do begin
  498.                             if rtnCode = noErr then begin
  499.                                 cer.event := C_Found;
  500.                                 cer.value := addrs[1];
  501.                             end
  502.                             else if done <> 0 then begin
  503.                                 cer.event := C_SearchFailed;
  504.                                 cer.value := rtnCode;
  505.                             end
  506.                             else if TickCount > timeout then begin
  507.                                 cer.event := C_SearchFailed;
  508.                                 cer.value := 1;
  509.                                 cer.timedout := true;
  510.                             end;
  511.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  512.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  513.                                     DisposPtr(ptr(cacheFaultReturnP));
  514.                                 cacheFaultReturnP := nil;
  515.                                 DestroyConnection(rcp);
  516.                             end; {if}
  517.                         end; {with}
  518.                     CS_Opening: 
  519.                         begin
  520.                         laststate := MyTCPState(tcpc);
  521.                         tcpstates[laststate] := true;
  522.                         case laststate of
  523.                             T_WaitingForOpen, T_Opening, T_Listening: 
  524.                                 if TickCount > timeout then begin
  525.                                     CloseConnection(rcp);
  526.                                     cer.event := C_FailedToOpen;
  527.                                     cer.timedout := true;
  528.                                 end;
  529.                             T_Established: 
  530.                                 begin
  531.                                 cer.event := C_Established;
  532.                                 status := CS_Established;
  533.                                 timeout := maxLongInt;
  534.                             end;
  535.                             T_PleaseClose, T_Closing: 
  536.                                 begin
  537.                                 CloseConnection(rcp);
  538.                                 cer.value := 1;
  539.                                 cer.event := C_FailedToOpen;
  540.                                 timeout := TickCount + TO_Closing;
  541.                             end;
  542.                             T_Closed: 
  543.                                 begin
  544.                                 status := CS_Closing;
  545.                                 cer.value := 2;
  546.                                 cer.event := C_FailedToOpen;
  547.                                 timeout := TickCount + TO_Closing;
  548.                             end;
  549.                             otherwise
  550.                                 ;
  551.                         end; {case }
  552.                     end;
  553.                     CS_Established: 
  554.                         begin
  555.                         laststate := MyTCPState(tcpc);
  556.                         tcpstates[laststate] := true;
  557.                         case laststate of
  558.                             T_Established: 
  559.                                 begin
  560.                                 cer.value := TCPCharsAvailable(tcpc);
  561.                                 if cer.value > 0 then
  562.                                     cer.event := C_CharsAvailable;
  563.                             end;
  564.                             T_PleaseClose, T_Closing: 
  565.                                 begin
  566.                                 cer.value := TCPCharsAvailable(tcpc);
  567.                                 if cer.value > 0 then
  568.                                     cer.event := C_CharsAvailable
  569.                                 else begin
  570. {    CloseConnection(rcp);}
  571.                                     status := CS_Closing;
  572.                                     cer.event := C_Closing;
  573.                                     timeout := TickCount + TO_Closing;
  574.                                 end;
  575.                             end;
  576.  
  577.                             T_Closed: 
  578.                                 begin
  579.                                 status := CS_Closing;
  580.                                 cer.event := C_Closing;
  581.                                 timeout := TickCount + TO_Closing;
  582.                             end;
  583.                             otherwise
  584.                                 ;
  585.                         end;
  586.                     end;
  587.                     CS_Closing: 
  588.                         begin
  589.                         laststate := MyTCPState(tcpc);
  590.                         tcpstates[laststate] := true;
  591.                         case laststate of
  592.                             T_WaitingForOpen, T_Opening, T_Listening: 
  593.                                 DebugStr('Strange State 2');
  594.                             T_PleaseClose, T_Closing, T_Established: 
  595.                                 begin
  596.                                 cer.value := TCPCharsAvailable(tcpc);
  597.                                 if cer.value > 0 then
  598.                                     cer.event := C_CharsAvailable
  599.                                 else if TickCount > timeout then begin
  600.                                     cer.event := C_Closed;
  601.                                     if tcpc <> nil then begin
  602.                                         oe := TCPAbort(tcpc);
  603.                                         oe := TCPRelease(tcpc);
  604.                                     end;
  605.                                     cer.timedout := true;
  606.                                     DestroyConnection(rcp);
  607.                                 end;
  608.                             end;
  609.                             T_Closed: 
  610.                                 begin
  611.                                 cer.event := C_Closed;
  612.                                 if tcpc <> nil then
  613.                                     oe := TCPRelease(tcpc);
  614.                                 DestroyConnection(rcp);
  615.                             end;
  616.                             otherwise
  617.                                 ;
  618.                         end;
  619.                     end;
  620.                     otherwise
  621.                         ;
  622.                 end;
  623.  
  624.                 if (cer.event = C_NoEvent) & (TickCount > heartbeat) then begin
  625.                     cer.event := C_HeartBeat;
  626.                     heartbeat := TickCount + period;
  627.                 end;
  628.                 if cer.event <> C_NoEvent then
  629.                     constates[cer.event] := true;
  630.             end;{with}
  631.         end;{HandleConnection}
  632.         var
  633.             oci: connectionIndex;
  634.     begin
  635.         cer.event := C_NoEvent;
  636.         if cp <> any_connection then begin
  637.             if ValidConnection(cp) then
  638.                 HandleConnection(cp);
  639.         end
  640.         else begin
  641.             oci := connectionItem;
  642.             repeat
  643.                 if connections[connectionItem].magic = TCPCMagic then begin
  644.                     HandleConnection(connectionItem);
  645.                 end;{if}
  646.                 if connectionItem = max_connections then
  647.                     connectionItem := 1
  648.                 else
  649.                     connectionItem := connectionItem + 1;
  650.             until (oci = connectionItem) or (cer.event <> C_NoEvent);
  651.         end;{if}
  652.         GetConnectionEvent := cer.event <> C_NoEvent;
  653.     end;{GetConnectionEvent}
  654.  
  655. end.